// go_demo.go - SecureConfig命令行工具的Go演示程序
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

// 响应结构体
type SecureConfigResponse struct {
	Status  string      `json:"status"`
	Message string      `json:"message,omitempty"`
	Configs []string    `json:"configs,omitempty"`
	Count   int         `json:"count,omitempty"`
	Data    interface{} `json:"data,omitempty"`
	Value   interface{} `json:"value,omitempty"`
	NewKey  string      `json:"new_key,omitempty"`
}

// 颜色代码
const (
	colorReset  = "\033[0m"
	colorRed    = "\033[31m"
	colorGreen  = "\033[32m"
	colorYellow = "\033[33m"
	colorBlue   = "\033[34m"
	colorCyan   = "\033[36m"
)

// 执行secureconfig命令并返回结果
func runSecureconfigCommand(command string, args ...string) (*SecureConfigResponse, error) {
	cmdArgs := append([]string{command, "-f", "json"}, args...)
	fmt.Printf("%s正在执行命令: secureconfig %s%s\n", colorYellow, strings.Join(cmdArgs, " "), colorReset)

	cmd := exec.Command("secureconfig", cmdArgs...)
	output, err := cmd.CombinedOutput()
	outputStr := string(output)

	if err != nil {
		// 尝试解析错误输出是否包含JSON
		jsonStart := strings.Index(outputStr, "{")
		if jsonStart >= 0 {
			jsonOutput := outputStr[jsonStart:]
			var response SecureConfigResponse
			if jsonErr := json.Unmarshal([]byte(jsonOutput), &response); jsonErr == nil {
				return &response, nil
			}
		}
		return &SecureConfigResponse{
			Status:  "error",
			Message: fmt.Sprintf("命令执行失败: %v, 输出: %s", err, outputStr),
		}, err
	}

	// 解析JSON响应
	jsonStart := strings.Index(outputStr, "{")
	if jsonStart >= 0 {
		outputStr = outputStr[jsonStart:]
	}

	var response SecureConfigResponse
	if err := json.Unmarshal([]byte(outputStr), &response); err != nil {
		return &SecureConfigResponse{
			Status:  "error",
			Message: fmt.Sprintf("解析输出失败: %v, 原始输出: %s", err, outputStr),
		}, err
	}

	return &response, nil
}

// 打印结果
func printResult(title string, result *SecureConfigResponse) {
	fmt.Printf("\n%s==== %s ====%s\n", colorCyan, title, colorReset)
	if result.Status == "success" {
		jsonData, _ := json.MarshalIndent(result, "", "  ")
		fmt.Println(string(jsonData))
	} else {
		fmt.Printf("%s失败: %s%s\n", colorRed, result.Message, colorReset)
	}
}

func main() {
	// 设置主密钥环境变量
	os.Setenv("SECURECONFIGMASTERKEY", "your_master_key_here")

	// 计时开始
	startTime := time.Now()

	fmt.Printf("\n%s===== 第一部分: 常规加解密操作 =====%s\n", colorCyan, colorReset)

	// 1. 创建 json 配置文件
	jsonName := "demo_json"
	fmt.Printf("创建 json 配置文件: %s\n", jsonName)
	result, _ := runSecureconfigCommand("create", jsonName, "--type", "json", "--force")
	printResult("创建 json 配置", result)

	// 2. set-value 仅支持 json
	fmt.Printf("设置 json 配置的值: %s app.version = 2.0.0\n", jsonName)
	result, _ = runSecureconfigCommand("set-value", jsonName, "app.version", "2.0.0")
	printResult("设置 json 配置值", result)

	// 3. get-value 仅支持 json
	fmt.Printf("获取 json 配置的值: %s app.version\n", jsonName)
	result, _ = runSecureconfigCommand("get-value", jsonName, "app.version")
	printResult("获取 json 配置值", result)

	// 4. 创建 text 文件
	textName := "demo_text"
	fmt.Printf("创建 text 文件: %s\n", textName)
	result, _ = runSecureconfigCommand("create", textName, "--type", "text", "--force")
	printResult("创建 text 文件", result)

	// 5. 保存明文内容到 text 文件
	textPath := filepath.Join("configs", textName+".txt")
	// 确保目录存在
	os.MkdirAll(filepath.Dir(textPath), 0755)
	err := ioutil.WriteFile(textPath, []byte("Hello, SecureConfig!\n这是一个文本文件。"), 0644)
	if err != nil {
		fmt.Printf("%s写入文件失败: %v%s\n", colorRed, err, colorReset)
		return
	}
	fmt.Printf("已写入明文内容到 %s\n", textPath)

	// 6. 加密 text 文件
	fmt.Printf("加密 text 文件: %s\n", textName)
	result, _ = runSecureconfigCommand("encrypt", textName, "--type", "text")
	printResult("加密 text 文件", result)

	// 7. 解密 text 文件
	fmt.Printf("解密 text 文件: %s\n", textName)
	result, _ = runSecureconfigCommand("decrypt", textName, "--type", "text")
	printResult("解密 text 文件", result)

	// 8. 创建 binary 文件
	binaryName := "demo_bin"
	fmt.Printf("创建 binary 文件: %s\n", binaryName)
	result, _ = runSecureconfigCommand("create", binaryName, "--type", "binary", "--force")
	printResult("创建 binary 文件", result)

	// 9. 保存明文内容到 binary 文件
	binaryPath := filepath.Join("configs", binaryName+".bin")
	// 确保目录存在
	os.MkdirAll(filepath.Dir(binaryPath), 0755)
	err = ioutil.WriteFile(binaryPath, []byte{0, 1, 2, 3, 4, 5, 6, 7}, 0644)
	if err != nil {
		fmt.Printf("%s写入文件失败: %v%s\n", colorRed, err, colorReset)
		return
	}
	fmt.Printf("已写入明文内容到 %s\n", binaryPath)

	// 10. 加密 binary 文件
	fmt.Printf("加密 binary 文件: %s\n", binaryName)
	result, _ = runSecureconfigCommand("encrypt", binaryName, "--type", "binary")
	printResult("加密 binary 文件", result)

	// 11. 解密 binary 文件
	fmt.Printf("解密 binary 文件: %s\n", binaryName)
	result, _ = runSecureconfigCommand("decrypt", binaryName, "--type", "binary")
	printResult("解密 binary 文件", result)

	fmt.Printf("\n%s===== 第二部分: 原地加解密操作 (使用 --inplace 参数) =====%s\n", colorCyan, colorReset)

	// 12. 创建原地加密演示文件
	inplaceName := "inplace_demo"
	jsonPath := filepath.Join("configs", inplaceName+".json")
	backupPath := filepath.Join("configs", inplaceName+"_backup.json")

	fmt.Printf("创建原地加密演示 json 文件: %s\n", inplaceName)
	result, _ = runSecureconfigCommand("create", inplaceName, "--type", "json", "--force")
	printResult("创建原地加密演示文件", result)

	// 13. 设置演示文件内容
	fmt.Printf("设置演示文件值: %s\n", inplaceName)
	runSecureconfigCommand("set-value", inplaceName, "demo.name", "原地加密演示")
	result, _ = runSecureconfigCommand("set-value", inplaceName, "demo.description", "这是一个测试原地加密功能的文件")

	// 14. 解密后备份原始明文文件（用于对比）
	result, _ = runSecureconfigCommand("decrypt", inplaceName, "--type", "json")
	copyFile(jsonPath, backupPath)
	printResult("设置演示文件值", result)
	fmt.Printf("已备份明文文件到 %s\n", backupPath)

	// 15. 原地加密
	fmt.Printf("原地加密文件: %s (使用 --inplace 参数)\n", inplaceName)
	result, _ = runSecureconfigCommand("encrypt", inplaceName, "--type", "json", "--inplace")
	printResult("原地加密", result)

	// 16. 验证原地加密结果
	encryptedJsonExists := fileExists(filepath.Join("configs", inplaceName+".json.enc"))
	originalJsonExists := fileExists(jsonPath)
	fmt.Printf("加密文件 (%s.json.enc) 是否存在? %v\n", inplaceName, encryptedJsonExists)
	fmt.Printf("原始文件 (%s.json) 是否存在? %v (原地加密，应该存在)\n", inplaceName, originalJsonExists)

	// 17. 原地解密
	fmt.Printf("原地解密文件: %s (使用 --inplace 参数)\n", inplaceName)
	result, _ = runSecureconfigCommand("decrypt", inplaceName, "--type", "json", "--inplace")
	printResult("原地解密", result)

	// 18. 验证文件是否相同
	areFilesIdentical := compareFiles(jsonPath, backupPath)
	fmt.Printf("原地加解密后的文件与原始文件是否相同? %v\n", areFilesIdentical)

	// 19. 清理演示文件
	fmt.Printf("\n%s===== 清理演示文件 =====%s\n", colorCyan, colorReset)
	filesToDelete := []string{jsonName, textName, binaryName, inplaceName}

	for _, name := range filesToDelete {
		fmt.Printf("删除文件: %s\n", name)
		runSecureconfigCommand("delete", name, "--type", "json")
	}

	if fileExists(backupPath) {
		err := os.Remove(backupPath)
		if err != nil {
			fmt.Printf("%s删除备份文件失败: %v%s\n", colorRed, err, colorReset)
		} else {
			fmt.Printf("已删除备份文件: %s\n", backupPath)
		}
	}

	// 20. 演示 get-value/set-value 仅支持 json 的限制
	fmt.Printf("\n%s===== 演示 get-value/set-value 仅支持 json 的限制 =====%s\n", colorCyan, colorReset)

	fmt.Printf("尝试对 text 文件使用 get-value (应报错)\n")
	result, _ = runSecureconfigCommand("get-value", textName, "app.version", "--type", "text")
	printResult("get-value 用于 text 类型", result)

	fmt.Printf("尝试对 binary 文件使用 get-value (应报错)\n")
	result, _ = runSecureconfigCommand("get-value", binaryName, "app.version", "--type", "binary")
	printResult("get-value 用于 binary 类型", result)

	// 计算总耗时
	endTime := time.Now()
	totalTime := endTime.Sub(startTime).Seconds()
	fmt.Printf("\n%s全部演示完成，总耗时: %.2f 秒%s\n", colorGreen, totalTime, colorReset)
}

// 辅助函数：文件是否存在
func fileExists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

// 辅助函数：复制文件
func copyFile(src, dst string) error {
	data, err := ioutil.ReadFile(src)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(dst, data, 0644)
}

// 辅助函数：比较两个文件
func compareFiles(file1, file2 string) bool {
	data1, err1 := ioutil.ReadFile(file1)
	data2, err2 := ioutil.ReadFile(file2)

	if err1 != nil || err2 != nil {
		fmt.Printf("比较文件时出错: %v, %v\n", err1, err2)
		return false
	}

	return string(data1) == string(data2)
}

/*
使用方法:
1. 确保已安装SecureConfig工具
2. 确保已安装Go环境
3. 运行: go run demo/go_demo.go
*/ 